import is.glif.fenius.ws.draft.DraftFeniusService;
import is.glif.fenius.ws.draft.Draft;

import is.glif.fenius.ws.draft.ReservationParams;
import is.glif.fenius.ws.draft.EndpointPair;
import is.glif.fenius.ws.draft.ExplicitRoute;
import is.glif.fenius.ws.draft.EndpointParams;
import is.glif.fenius.ws.draft.CommonParams;
import is.glif.fenius.ws.draft.DomainParams;
import is.glif.fenius.ws.draft.Status;
import is.glif.fenius.ws.draft.TimeParams;

import is.glif.fenius.ws.draft.CreateReq;
import is.glif.fenius.ws.draft.CreateResp;
import is.glif.fenius.ws.draft.ListReq;
import is.glif.fenius.ws.draft.ListResp;
import is.glif.fenius.ws.draft.CancelReq;
import is.glif.fenius.ws.draft.CancelResp;

import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.namespace.QName;

import java.net.URL;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.IOException;
import java.io.FileInputStream;

import java.util.List;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.GregorianCalendar;
import java.util.Enumeration;
import java.util.Map;

import org.ho.yaml.Yaml;

public class DraftRrmTimetable {
    static boolean debug = true;
    static int GROUP_ID_POSOTION = 4;
    static int HTTP_SERVER_PORT = 9090;

    public Hashtable<String, ReservationParams> timetable = 
	new Hashtable<String, ReservationParams>();
    public ArrayList<DraftFeniusService> fs = new ArrayList<DraftFeniusService>();
    public int interval = 5000;

    public QName qname = new QName("http://fenius.glif.is/ws/draft/", "draft");
    public URL[] urls = null;
    public DraftFeniusService[] ports = null;
    public Thread[] collectors = null;
    static String[] surls = null;

    static {
        loadConfig("/home/okazaki/INSTALL/gridars3/java/nrm/test/feniusclient/config.yml" );
    }


    public DraftRrmTimetable() 
    {
	TimeZone.setDefault(TimeZone.getTimeZone("UTC"));

	if (surls == null || surls.length == 0) return;
	urls = new URL[surls.length];
	ports = new DraftFeniusService[surls.length];
	collectors = new Thread[surls.length];

	for (int i = 0; i < surls.length; i++) {
	    try {
		urls[i] = new URL(surls[i]);
		Draft service = new Draft(urls[i], qname);
		ports[i] = service.getDraftFeniusServicePort();
	    } catch (Exception ex) {
		System.err.println(ex);
	    }
	}

	if (false) {
	    Thread timeKeeper = new Thread(new Runnable() {
		    public void run() {
			while (true) {
			    update();
			    try {
				Thread.sleep(interval);
			    } catch (InterruptedException e) {
				e.printStackTrace();
			    }
			}
		    }
		});
	    timeKeeper.start();
	}

	Thread server = new Thread(new Runnable() 
	    {
		public void run() 
		{
		    ServerSocket socket = null;
		    try {
			socket = new ServerSocket(HTTP_SERVER_PORT);
		    } catch (IOException ex) {
			System.err.println(ex);
			return;
		    }
			
		    while (true) {
			Socket s = null;
			try {
			    s = socket.accept();
			    httpService(s);
			    s.close();
			} catch (IOException ex) {
			    System.err.println(ex);
			    try {
				if (s != null) s.close();
			    } catch (IOException e) {}
			}
		    }
		}
		
	    });
	server.start();
    }

    public void httpService(Socket socket)
	throws IOException
    {
	InputStream is = socket.getInputStream();
	InputStreamReader ir = new InputStreamReader(is);
	BufferedReader in = new BufferedReader(ir);
	
	OutputStream os = socket.getOutputStream();
	PrintWriter out = new PrintWriter(os, true);
		    
	String line = null;
	while ((line = in.readLine()) != null) {
	    // if (debug) System.err.println("Monitor:input="+ line);
	    if (line.startsWith("GET /rnds")) break;
	    if (line == "") return;
	}
	update();
	String s = toXML();
	out.println(s);
	if (debug) System.err.println(s);
    }
    
    public synchronized void update() {
	for (int i = 0; i < collectors.length; i++) {
	    final int index = i;
	    collectors[i] = new Thread(new Runnable() {
		    public void run() {
			try {
			    if (ports[index] == null) {
				Draft service = new Draft(urls[index], qname);
				ports[index] = service.getDraftFeniusServicePort();
			    }
			    if (ports[index] == null) return;
			    
			    ReservationParams[] rp = list(ports[index]);
			    if (rp != null || rp.length != 0) {
				for(int k = 0; k < rp.length; k ++) {
				    String id = rp[k].getReservationId() + "[" + index + "]";
				    timetable.put(id, rp[k]);
				}
			    }
			} catch (Exception ex) {
			    if (debug) System.err.println("ws error:" + urls[index]);
			    ports[index] = null;
			}
		    }
		});
	    collectors[i].start();
	}

	for (int i = 0; i < collectors.length; i++) {
	    try {
		collectors[i].join();
	    } catch (InterruptedException ex) {}
	}
    }

    public String toXML()
    {
	String s = 
	    "<?xml version=\"1.0\"?>\n" +
	    "<reservationIDMaps xmlns=\"http://glambda/schema/2006/07/demo\"\n" +
	    "  xmlns:demo=\"http://glambda/schema/2006/07/demo\"\n" +
	    "  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
	    "  xsi:schemaLocation=\"http://glambda/schema/2006/07/demo demo.xsd\">\n" +
	    "<reservationIDMap sched=\"AIST-GRS\">\n\n";

	Enumeration e = (Enumeration) timetable.keys();
	while (e.hasMoreElements()) {
            String id = (String) e.nextElement();
	    ReservationParams p = timetable.get(id);

	    if (p == null) continue;

	    String rid = p.getReservationId();
	    String ap = p.getEndpoints().getA();
	    String zp = p.getEndpoints().getZ();
	    String st = mapStatus(p.getEndtoendParams().getStatus());
	    String bw = "" + p.getEndtoendParams().getBandwidth() * 1000;
	    XMLGregorianCalendar gc = 
		p.getEndtoendParams().getTimeParams().getScheduledStartTime();
	    String stime = gc.toString();
	    stime = stime.substring(0, 19) + "Z";
	    gc = p.getEndtoendParams().getTimeParams().getScheduledEndTime();
	    String etime = gc.toString();
	    etime = etime.substring(0, 19) + "Z";

	    String setid = id.substring(0, GROUP_ID_POSOTION);

	    s += "  <resourceSet id=\"" + setid + "\" distinguishedName=\"O=Grid, CN=fenius\">\n";
	    s += "    <networkResource APoint=\"" + ap + "\" ZPoint=\"" + zp + "\">\n";
	    s += "      <path name=\"nrm0-factoryurl\" reservationID=\"" + id + "\">\n";
	    s += "        <startTime value=\"" + stime + "\"/>\n";
	    s += "        <endTime value=\"" + etime + "\"/>\n";
	    s += "        <reservationStatus value=\"" + st + "\"/>\n";
	    s += "        <aPoint value=\"" + ap + "\"/>\n";
	    s += "        <zPoint value=\"" + zp + "\"/>\n";
	    s += "         <bandwidth value=\"" + bw + "\"/>\n";
	    s += "      </path>\n";
	    s += "    </networkResource>\n";
	    s += "  </resourceSet>\n\n";
	}

	s += "</reservationIDMap>\n";
	s += "</reservationIDMaps>\n";

	return s;
    }

    public String mapStatus(Status s) 
    {
	String r = null;

	if (Status.REQUESTING == s) r = "Prepeared";
	else if (Status.RESERVED == s) r = "Reserved";
	else if (Status.INSETUP == s) r = "Reserved";
	else if (Status.ACTIVE == s) r = "Activated";
	else if (Status.INTEARDOWN == s) r = "Released";
	else if (Status.FINISHED == s) r = "Released";
	else if (Status.CANCELLED == s) r =  "Released";
	else if (Status.FAILED == s) r = "Error";
	else r = "Unknown";

	// if (debug) System.err.println("Status=" + s.toString() + ", return=" + r);
	return r;
    }

    public boolean create(DraftFeniusService port, ReservationParams p) 
    {
	if (port == null) return false;

	try {
	    if (debug) printParams("Create request", p);
	    CreateReq req = new CreateReq();
	    req.setResvParams(p);

	    CreateResp res = port.create(req);

	    ReservationParams rp = res.getResvParams();
	    if (debug) printParams("Create response", rp);
	} catch (Exception e) {
	    e.printStackTrace();
	    return false;
	}
	return true;
    }

    public ReservationParams[] list(DraftFeniusService port) 
    {
	if (port == null) return null;

	try {
	    ListReq req = new ListReq();

	    ListResp res = port.list(req);

	    List<ReservationParams> rps = res.getReservations();
	    if (rps == null) return null;

	    int size = rps.size();
	    ReservationParams[] rp = new ReservationParams[size];
	    ReservationParams[] rpp = rps.toArray(rp);
	    for (int i = 0; i < size; i++) {
	       if (debug) printParams("List response", rpp[i]);
	    }
	    return rpp;
	} catch (Exception e) {
	    e.printStackTrace();
	    return null;
	}
    }

    public boolean cancel(DraftFeniusService port, String id)
    {
	if (port == null) return false;

	try {
	    if (debug) printParams("Cancel request", null);

	    CancelReq req = new CancelReq();
	    req.setReservationId(id);
	    req.setUserName("fenius-user");
	    req.setUserGroup("fenius-group");

	    CancelResp res = port.cancel(req);

	    Status status = res.getStatus();
	    if (debug) System.err.println("Cancel result = " + status.toString());
	} catch (Exception e) {
	    e.printStackTrace();
	    return false;
	}
	return true;
    }

    private void printParams(String m, ReservationParams p)
    {
	String s = m + ":\n";
	if (p != null) {
	    m += "\t" + p.getReservationId() 
		+ "::" + p.getEndpoints().getA()
		+ "->" + p.getEndpoints().getZ()
		+ ":" + p.getEndtoendParams().getStatus().toString();

	    XMLGregorianCalendar c = 
		p.getEndtoendParams().getTimeParams().getScheduledStartTime();
	    m += ", From " + c.getYear() + "/" + c.getMonth() + "/" + c.getDay();
	    m += " " + c.getHour() + ":" + c.getMinute() + ":" + c.getSecond();

	    c = p.getEndtoendParams().getTimeParams().getScheduledEndTime();
	    m += ", To " /* + c.getYear() + "/" + c.getMonth() + "/" + c.getDay() */;
	    m += " " + c.getHour() + ":" + c.getMinute() + ":" + c.getSecond();

	    m += ", BW=" + p.getEndtoendParams().getBandwidth();
	}
	System.out.println(m);
    }

    @SuppressWarnings({ "static-access", "unchecked" })
	static public void loadConfig(String config)
    {
	ArrayList l = new ArrayList<String>();
        try {
            if (config == null) {
                throw new Exception("Config file name is null.");
            }
            System.err.println("=========== config:" + config);
            String configFile = config;
	    
            InputStream propFile = new FileInputStream(configFile);
            Map baseConfig = (Map) Yaml.load(propFile);

            ArrayList<Map> servicesConfig =
                (ArrayList<Map>) baseConfig.get("fenius-services");
            for (Map serviceConfig : servicesConfig) {
                String url = (String) serviceConfig.get("url");
                String domain = (String) serviceConfig.get("domain");
                String user = (String) serviceConfig.get("user");
                String password = (String) serviceConfig.get("password");

		l.add(url);
	    }
	} catch (Exception ex) {
            System.err.println("=========== config: error");
            ex.printStackTrace();
	}
	surls = (String[]) l.toArray(new String[l.size()]);
    }



    public static void main(String[] args) {
	String[] url = {
	    "http://163.220.30.149:8080/DraftFeniusService?wsdl",
	    "http://163.220.30.149:8081/DraftFeniusService?wsdl",
	    "http://163.220.30.149:8082/DraftFeniusService?wsdl",
	    "http://163.220.30.149:8083/DraftFeniusService?wsdl",
	    "http://163.220.30.149:8084/DraftFeniusService?wsdl"
	};
	DraftRrmTimetable t = new DraftRrmTimetable();
    }
}